---
--类名: MapManager.lua
--创建日期: 2016-8-22
--创建人: 陈小虎
--功能描述:
--修改内容:
--修改日期:
--修改人:
--修改备注:
--
local Map = import("..views.Map")
local TaskSequence = require("app.utils.TaskSequence")
local AvatarFactory = require("app.public.avatar.AvatarFactory")

local MapManager = class("MapManager")

local math_min = math.min
local math_max = math.max

function MapManager:ctor()
    cc(self):addComponent("components.behavior.EventProtocol"):exportMethods()

    -- self._lines = {}
    self._mapPathPoints = {}

    self._isEnterGame = false    -- 是否已经进入游戏
    self._isChangeMap = false    -- 是否在地图切换中
    self._isInChangeMapAni = false -- 是否在切换动画中，主要是角色的动画

    self._nextEnterMapMsg = nil -- 缓存传送中收到的服务器传送消息，在传送完成后执行
    self._nextChangeMapParams = nil -- 缓存传送中收到的切换地图参数，在传送完成后执行

    self._isNextChangeMapIgnoreAni = false -- 下次传送是否忽略动画

    self:clear()
end

-- 复位状态
function MapManager:clear()
	self:setExtraScaleRate(0)
	self:setParallaxNode(nil)
    self:stopCameraZoomForStory(false)
    self:pauseEventAutoAdjustCamera(false)
    self:pauseAdjustCamera(false)
    self:pauseRunCameraZoomForEvent(false)
    -- self:clearLinesData()
    -- self:setBorderLeftX(-1)
    -- self:setBorderRightX(-1)
    self:setGroundNode(nil)
    self:clearPath()
    self:setCameraX(0)
    self:setCameraY(0)
end

function MapManager:updateFrame(dt)
    local map = self._map
    if not map then return end
    map:updateFrame(dt)
end

function MapManager:intoWorld(parent,zOrder)
    self._world = display.newLayer()
    parent:addChild(self._world,zOrder)

    NodeFactory:setNodeParent(self._world)

    self._map = Map.new()
    self._world:addChild(self._map)

    NpcFactory:setNpcParent(self._map)

    local nameParent = display.newLayer()
    self._world:addChild(nameParent)
    NodeFactory:setNameParent(nameParent)
end

function MapManager:outWorld(parent)
    if not self._world then return end

    display.setBlurNode(nil)
    display.setBeforeBlurCallback(nil)
    display.setAfterBlurCallback(nil)
    display.setFinishBlurCallback(nil)

    parent:removeChild(self._world)
    self._world = nil
    self:clear()

    UIHandler:clearTouchMask()
    NodeFactory:clearBubble()
    FieldManager:clear()
    TeamManager:clear()
    StoryManager:clear()
    BattleManager:clear()
    NpcManager:clear()
    FieldManager:getWeatherSystem():resetData()
    DoEventHandler.removeCloud()
end

function MapManager:getWorld()
    return self._world
end

function MapManager:setParent(parent)
    self._parent = parent
end

function MapManager:isEnterGame()
    return self._isEnterGame
end

function MapManager:checkNextEnterMapMsg()
    if self._nextEnterMapMsg then
        self._nextChangeMapParams = nil
        self:onParseEnterMap(self._nextEnterMapMsg)
        self._nextEnterMapMsg = nil
    end
end

-- 设置下一次地图传送，忽略动画，立即传送
function MapManager:setNextChangeMapIgnoreAni(b)
    self._isNextChangeMapIgnoreAni = b
end

function MapManager:onParseEnterMap(msg)
    if DoEventHandler.isSimulation then return end
    print("MapManager.onParseEnterMap", self._isEnterGame, self._isChangeMap, msg.mapId ~= self._mapId)

    if self._isChangeMap then
        self._nextEnterMapMsg = msg
        return
    end

    if self._isEnterGame then
        self:callSendEnterMap(msg.mapId)
        if msg.mapId ~= self._mapId then
            self:gotoMap({mapId=msg.mapId, transX=msg.posX, service=true, ignoreAni=self._isNextChangeMapIgnoreAni})
            self._isNextChangeMapIgnoreAni = false
        else
            -- 星空谜棋地图不需要同步位置
            if not app:sendMsg("ChessModel", "isChessMap") then
                FieldManager:adjustSelfToFixedPosition(msg.posX)
            end
            -- 断线重连之后重新设置一次scale
            if self._map then
                local scale = app:getValue("UserMapScale", 0)
                if scale ~= 0 then
                    self._map:setZoomScale(scale)
                end
            end
        end
    else
        self._isChangeMap = true
        self._nextEnterMapMsg = nil
        app:sendMsg("LoadingController", "enterMapLoading", msg)
    end
end

function MapManager:enterMapRequest(mapId,confirmNpcId)
    local mapConfig
    local dungeonId
    local dungeonSubId

    if confirmNpcId then
        local npcC = NpcManager:getNpcConfigById(confirmNpcId)
        if npcC and npcC.ID then
            local func = tonumber(npcC["function"])
            local funcPar = npcC["functionPar"]
            if func == 51 and funcPar then
                local fArray = string.split(funcPar,"|")
                local mId = tonumber(fArray[1])
                if mId then
                    mapId = mId
                    mapConfig = GD:queryMapById(mapId)
                end
            elseif func == 53 and funcPar then
                local array = string.split(funcPar,";")
                if #array >= 2 then
                    local dArray = string.split(array[1],"|")
                    if #dArray >= 3 then
                        if UD:getCurTaskId() <= tonumber(dArray[1]) then
                            dungeonId = tonumber(dArray[2])
                            dungeonSubId = tonumber(dArray[3])
                        end
                    end
                end
            end
        end
    end

    if self:popErrorMapMessage(mapId) then
        return
    end

    -- 剧情副本
    if dungeonId and dungeonSubId then
        StoryManager:clearTransferStatus()
        NpcManager:reqEnterTaskDungeon(dungeonId, dungeonSubId)
        return
    end

    if not mapConfig or not mapConfig.ID then
        mapConfig = GD:queryMapById(mapId)
    end

    if mapConfig and mapConfig.ID then
        local function enterFailed(msg)
            FieldManager:setStopSendPosition(false)
            StoryManager:clearTransferStatus()
        end
        local function enterOk(msg)
            if tonumber(mapId) == self._mapId then
                FieldManager:setStopSendPosition(false)
            end
        end

        if app.session:isOpen() then
            FieldManager:setStopSendPosition(true)
            local mapType = tonumber(mapConfig.maptype)
            if Enums.mapType[mapType] == "home" then--家园
                -- 废弃
            elseif Enums.mapType[mapType] == "dungeon" then
                if dungeonId and dungeonSubId then
                    DungeonManager:enterDungeonRequest(dungeonId,dungeonSubId,"normal",nil,enterFailed)
                else
                    enterFailed()
                end
            else
                self._sendEnterMap = true
                
                local params = {}
                params.mapId = mapId
                params.npcId = confirmNpcId
                params.faceTo = FieldManager:getCharacterDirection()
                app.session:request("pb_map.C2S_EnterMap", params,enterOk,{block = false},enterFailed)
            end
        else
            StoryManager:clearTransferStatus()
        end
    end
end

function MapManager:requestTpInSameMap(npcId)
    app.session:request("pb_map.C2S_Portal", {npcId = npcId}, function(msg)
        print("on requestTpInSameMap success!")
    end)
end

function MapManager:callSendEnterMap(mapId)
    if self._sendEnterMap then
        self._sendEnterMap = false
        if tonumber(mapId) == self._mapId then
            FieldManager:setStopSendPosition(false)
        end
    end
end

function MapManager:popErrorMapMessage(mapId)
    local isPop = false
    local errorMsg = app:checkMapRes(mapId)
    if errorMsg then
        local msgNode = display.newMessageBox(errorMsg)
        UIHandler:addPopupUi(msgNode)
        isPop = true
        StoryManager:clearTransferStatus()
    end
    return isPop
end

-- params = {
--    mapId    地图id 
--    transNpcId    目标npcId
--    first    是否第一次进入地图（登录游戏后的第一次）
--    transX    地图目标点x坐标
--    service    是否是服务器发来的消息驱动
--    confirmNpcId    确定npcId，从配置获取地图或地下城等信息
--    ignoreAni    不播放动画
-- }
function MapManager:gotoMap(params)
    local mapId = params.mapId
    local service = params.service
    local confirmNpcId = params.confirmNpcId

    -- 需要请求服务器
    if not service then
        self:enterMapRequest(mapId, confirmNpcId)
        return
    end

    -- 已经在切换了，缓存数据
    if self._isChangeMap then
        self._nextChangeMapParams = params
        return 
    end

    -- 找不到地图
    if self:popErrorMapMessage(mapId) then return end

    -- 玩家播放传送动画
    self._isChangeMap = true
    UIHandler:removeAllUI()
    UIHandler:hideDesktop()
    FieldManager:stopTouch(true)
    if params.ignoreAni then
        self._isInChangeMapAni = true
        app:sendMsg("LoadingController", "changeMapLoading", params)
    else
        self:_playChangeMapStartAni(function()
            -- 动画结束进入loading
            app:sendMsg("LoadingController", "changeMapLoading", params)
        end)
    end
end

-- 切换开始动画
function MapManager:_playChangeMapStartAni(cb)
    local map = self._map
    if not map then return end
    if self._isInChangeMapAni then return end
    self._isInChangeMapAni = true

    local visible = not BattleManager:isInBattle()

    local function playCharacterAni(character)
        local isMySelf = character:isMySelf()
        if isMySelf then
            map:playChangeMapStartAnimation(cb, character, visible)

            local mercenarys = FieldManager:getFollowMercenarys()
            for _,merc in pairs(mercenarys) do
                if merc and merc:isVisible() then
                    map:playChangeMapStartAnimation(nil, merc, visible)
                end
            end
        else
            map:playChangeMapStartAnimation(nil, character, visible)
        end
    end

    local characters = FieldManager:getFollowCharacters()
    if #characters > 0 then
        -- 有队伍，有队员
        for _, character in pairs(characters) do
            playCharacterAni(character)
        end
    else
        -- 没有队伍，就自己一个人
        playCharacterAni(FieldManager:getMyCharacter())
    end
end

-- 切换结束动画
function MapManager:_playChangeMapEndAni()
    local map = self._map
    if not map then return end
    if not self._isInChangeMapAni then return end
    self._isInChangeMapAni = false

    local visible = not BattleManager:isInBattle()

    local function playCharacterAni(character)
        local isMySelf = character:isMySelf()
        if isMySelf then
            map:playChangeMapEndAnimation(nil, character, visible)

            local mercenarys = FieldManager:getFollowMercenarys()
            for _,merc in pairs(mercenarys) do
                if merc and merc:isVisible() then
                    map:playChangeMapEndAnimation(nil, merc, visible)
                end
            end
        else
            map:playChangeMapEndAnimation(nil, character, visible)
        end
    end

    local characters = FieldManager:getFollowCharacters()
    if #characters > 0 then
        -- 有队伍，有队员
        for _, character in pairs(characters) do
            playCharacterAni(character)
        end
    else
        -- 没有队伍，就自己一个人
        playCharacterAni(FieldManager:getMyCharacter())
    end
end

-- 重置
function MapManager:revertChangeMapStatus()
    FieldManager:setFollowCharactersOpacity(255)
    --self._isInChangeMapAni = false
end

function MapManager:doEnterMap(mapId,transNpcId,transX)
    --AudioManager.uncacheAll()
    local mapConfig = GD:queryMapById(self._mapId)
    if mapConfig and Enums.mapType[tonumber(mapConfig.maptype)] == "dungeon" and mapId == tonumber(mapConfig.parent) and mapConfig.exitnpc then
        transNpcId = tonumber(mapConfig.exitnpc)
    end
    local tNpcId = transNpcId

    -- TODO: mapId 隐藏的太深，创建地图的时候完全不知道是要创建哪张地图
    self:setMapId(mapId)

    -- 进入地图，清理支线引导
    app:sendMsg("GuideModel", "cancelSideTaskGuide")

    self:intoWorld(self._parent,SceneZOrder.mapZOrder)

    app:dispatchCustomEvent("EVENT_REFRESH_WANDERLAND_CONFIG")
    DungeonManager:goOutDungeon()

    display.setBlurNode(self._world)

    display.setBeforeBlurCallback(function()
        NpcManager:allMapNpcsVisibility(false)
        FieldManager:allCharacterVisibility(false)
        FieldManager:hideSelfTaskFollowMercenarys()
        FieldManager:hideTeamTaskFollowMercenarys()
    end)

    display.setAfterBlurCallback(function()
        -- 战斗内不再设置场景中的显示状态
        if not BattleManager:isInBattle() then
            NpcManager:allMapNpcsVisibility(true)
            FieldManager:allCharacterVisibility(true)
            FieldManager:showSelfTaskFollowMercenarys()
            FieldManager:showTeamTaskFollowMercenarys()
        end
        self._world:setVisible(false)
    end)

    display.setFinishBlurCallback(function()
        self._world:setVisible(true)
    end)

    -- 关键方法，创建玩家的角色、摄像机
    local baseInfo
    if not app:isBattleGuideComp() then
        local guideRoles = app:sendMsg("NewerbattleguideModel", "getGuideRoles")
        baseInfo = guideRoles[1]:getBaseInfo()
    end
    FieldManager:createMyCharacter(transX, baseInfo)

    -- 人物角色创建好之后去重新更新一次，这时候会直接把随从添加在身上（这句话之前是在 createMyCharacter 前面的，现在移到后面，暂时看不出什么问题）
    FieldManager:doUpdateMapCharacters()

    FieldManager:getWeatherSystem():setMap(self._map)
    FieldManager:getWeatherSystem():initWeatherSystem()
    FieldManager:getWeatherSystem():playWeather()

    FieldManager:startUpdateFrame()

    if DoEventHandler.isNextCloudEvent() and not DoEventHandler.isPlayVideoEvent() then
        self:setHasChangeMapNextEvent(true)
        local isNext = DoEventHandler.nextEventsVec()
    end

end

function MapManager:doLeaveMap()
    DoEventHandler.clearGatherStatus()
    FieldManager:stopUpdateFrame()

    self:outWorld(self._parent)

    -- UIHandler:removeAllUI()
end

function MapManager:switchStartCallback()
    FieldManager:stopTouch(true)
    UIHandler:stopTouchParticle()
end

function MapManager:switchOverCallback(isFirstIntoGameLoading)
    if not self._world then return end

    -- 秘境
    if self:isIntoSecret() then
        self:setIntoSecret(false)
        StoryManager:clearTransferStatus()
    end

    -- 副本
    if self:isInDungeonMap() then
        app.session:request("pb_dungeon.C2S_GetDungeonInfo",{},
            function(msg) end, {block = false})
    end

    self:playMapMusic()

    self:forceCameraZoomToDest({dstScale = self:getMapScale(),time = 0,call = function()
        self:saveMapLayerScale()
    end})


    NpcManager:showAllNpcMark()
    UIHandler:removeBlackScreenMask()

    if not self:isHasChangeMapNextEvent() and not DoEventHandler.isPlayVideoEvent() then
        local isNext = DoEventHandler.nextEventsVec()
        if not isNext then
            StoryManager:clearAllStatus()
            app:dispatchCustomEvent("EVENT_NPC_TRACK",{start = false,hide = false})
        elseif DoEventHandler.isTracking() then
            local params = FieldManager:getAutoWayParams()
            if params and params.trackTaskId then
                app:dispatchCustomEvent("EVENT_START_TRACKING_STATUS")
            end
        end
    end

    if not BattleManager:isBattle() then
        FieldManager:stopTouch(false)
    end
    self._parent:startUpdateFrame()


    -- 战斗引导不上传位置
    if app:isBattleGuideComp() then
        FieldManager:setStopSendPosition(false)
    else
        FieldManager:setStopSendPosition(true)
    end

    UIHandler:showDesktop()

    app:dispatchCustomEvent("EVENT_MAP_SITE",{mapId = self._mapId})

    if isFirstIntoGameLoading then
        app.scene:onEnterGame()
        self._isEnterGame = true
    else
        self:_playChangeMapEndAni()
    end

    NpcFactory:addLoadNpcs()
    TaskManager:updateTaskOperation(UD:getCurTask(), "insert")
    ScriptManager:initTaskScript()
    -- 刷新所有活动npc
    NpcFactory:createAllActivityNpc()
    -- 刷新所有主线任务控制的npc mapset_opentask.csv
    NpcFactory:createAllMainTaskNpc()

    executeFunc(self._changeMapOverCB)
    self._changeMapOverCB = nil

    -- 切换场景时，如果通关奖励没显示，就去显示
    DungeonManager:showPassDungeonAward()

    print("MapManager:onMapChanged", self._mapId, isFirstIntoGameLoading)
    
    self._isChangeMap = false
    EM:notify("onMapChanged", isFirstIntoGameLoading)

    -- 下一个传送消息和当前地图一样，抛弃掉
    if self._nextEnterMapMsg and self._nextEnterMapMsg.mapId == self._mapId then
        self._nextEnterMapMsg = nil
    end

    -- guide
    self:checkGuide()

    local hasBattle, enterBattleInfo = UD:hasBattle(self._mapId)
    if hasBattle then
        -- 1. UD有战斗就触发UD的战斗
        UD:clearBattle()
        BattleManager:setEnterBattleInfo(enterBattleInfo)
        BattleManager:prepareBattle(true)
    elseif self._nextEnterMapMsg then
        -- 2. 还有地图传送消息，传送地图
        self:checkNextEnterMapMsg()
    else
        -- 3. 然后再触发地图战斗
        BattleManager:intoBattleAfterEnterMap()
    end
end

-- 检查是否触发了引导
function MapManager:checkGuide()
    local params = {
        scene = Constant.FUNC_TYPE_MAP,
        sceneSelf = self,
        getFunc = self.getGuideNodeFunc
    }
    EM:notify("checkGuide", params)
end

-- 获取引导node
function MapManager:getGuideNodeFunc(id, npcId)
    -- print("MapManager:getGuideNodeFunc", id, npcId)

    -- npc交互教学／采集教学
    local npc = NpcManager:getNpcById(npcId)
    if npc then
        local markNode = npc:getCurrentMark()
        if markNode then
            return markNode:getChildByName("Button")
        end
    end
end

function MapManager:setChangeMapOverCB(cb)
    self._changeMapOverCB = cb
end

function MapManager:clearPath()
    self._mapPathPoints = {}
end

function MapManager:addPathNode(line,node)
    if not node or not line then return end
    if not self._mapPathPoints[line] then
        self._mapPathPoints[line] = {}
    end
    table.insert(self._mapPathPoints[line],node)
end

function MapManager:getStandPointY(line, x)
    local node = self:getPathNode(line, x)
    if not node then return 0 end
    return node:getY(x)
end

-- binary search
function MapManager:getPathNode(line, x)
    if not line or not x then return end
    local linePoints = self._mapPathPoints[line]
    if not linePoints then return end

    local length = #linePoints
    local leftIndex = 1
    local rightIndex = length 

    while leftIndex <= rightIndex do
        local mid = math.floor((leftIndex + rightIndex) / 2)
        local node = linePoints[mid] 
        if x >= node.minX and x <= node.maxX then
            return node
        end

        if x < node.minX then
            rightIndex = mid - 1
        end
        if x > node.maxX then
            leftIndex = mid + 1
        end
    end

    return nil
end

function MapManager:addCharacterToMap(character,zOrder)
    self:dispatchEvent({name = "map_add_character",character = character,zOrder = zOrder})
end

function MapManager:setMapId(mapId)
    self._mapId = mapId
    self._mapConfig = GD:queryMapById(mapId)
    self._isSecretMap = (self._mapConfig and tonumber(self._mapConfig.wonderland) == 1)
end

function MapManager:getMapId()
    return self._mapId
end

function MapManager:isInDungeonMap()
    local mapType = Enums.mapType[tonumber(self._mapConfig.maptype)]
    return mapType == "dungeon"
end

-- 一般地图
function MapManager:isInNormalMap()
    local mapType = Enums.mapType[tonumber(self._mapConfig.maptype)]
    return mapType == "normal"
end

function MapManager:getMap()
    return self._map
end

function MapManager:getBorderLeftX()
    return self._borderLeftX
end

function MapManager:getBorderRightX()
    return self._borderRightX
end

-- 强制设置地图边界,但是不能超出地图范围
-- 人物行走范围以这里为准，不再依赖于 地图每层的配置节点
-- 地图行走层有三层，第二层是我自己所在层，这一层是必须要在地图资源文件里面配置的
-- 其他两层如果有就读配置，如果没有就拷贝第二层的数据
function MapManager:forceBorder(extents, PathNodeM)
    assert(self._mapPathPoints[2] , string.format( "Error: mapId = %d 第二层配置出错！！！", self:getMapId()) ) --@ignore

    -- 如果没有配置地图范围，就把第二层设置为地图范围
    if #extents == 0 then
        local linePoints = self._mapPathPoints[2]
        table.insert(extents, {left = math.floor(linePoints[1].minX), right = math.ceil(linePoints[#linePoints].maxX)}) -- 取整
    end

    self._borderLeftX = extents[1].left
    self._borderRightX = extents[#extents].right

    local copyLines = {1, 3}
    for _, line in ipairs(copyLines) do
        if self._mapPathPoints[line] == nil then
            local points = {}
            for __, node in ipairs(self._mapPathPoints[2]) do
                table.insert(points, node)
            end
            self._mapPathPoints[line] = points
        end
    end

    -- 把每一层的 左右端点坐标与 地图边界拉齐(如果超出了地图边界就不用处理)
    -- 通过新加一个段来处理，如果直接拉齐，当第一个段刚好是斜坡时就会出现问题
    for i = 1, 3 do
        local linePoints = self._mapPathPoints[i]
        local firstPoint = linePoints[1]

        if firstPoint.minX > self._borderLeftX then
            -- firstPoint.minX = self._borderLeftX
            local node = {minX = self._borderLeftX, maxX = firstPoint.minX, minY = firstPoint.minY, maxY = firstPoint.minY, length = firstPoint.minX - self._borderLeftX, height = 0}
            node.y = firstPoint.minY
            setmetatable(node, {__index = PathNodeM})
            table.insert(linePoints, 1, node) -- 插入到最前面
        end

        local endPoint = linePoints[#linePoints]
        if endPoint.maxX < self._borderRightX then
            -- endPoint.maxX = self._borderRightX
            local node = {minX = endPoint.maxX, maxX = self._borderRightX, minY = endPoint.maxY, maxY = endPoint.maxY, length = self._borderRightX - endPoint.maxX, height = 0}
            node.y = endPoint.maxY
            setmetatable(node, {__index = PathNodeM})
            table.insert(linePoints, node) -- 插入到后面
        end
    end

    self._mapExtents = extents
end

function MapManager:getExtentSection(x)
    for i, data in ipairs(self._mapExtents) do
        if x >= data.left and x <= data.right then
            return data
        end
    end

end

function MapManager:setIntoSecret(into)
    self._intoSecret = into
end

function MapManager:isIntoSecret()
    return self._intoSecret
end

function MapManager:isInHome()
    local inHome = false
    local homeMapConfig = GD:queryMapByType(4)
    if homeMapConfig and homeMapConfig.ID then
        if self._mapId == tonumber(homeMapConfig.ID) then
            inHome = true
        end
    end
    return inHome,homeMapConfig
end

function MapManager:isInMapType(t)
    local inGuild = false
    local mapConfig = GD:queryMapByType(t)
    if mapConfig and mapConfig.ID then
        if self._mapId == tonumber(mapConfig.ID) then
            inGuild = true
        end
    end
    return inGuild,mapConfig
end

function MapManager:isSecretMap()
    return self._isSecretMap or false
end

function MapManager:isChangeMap()
    return self._isChangeMap
end

function MapManager:resetMapFocus()
    if FieldManager:isStopEvent() then return end
    self:dispatchEvent({name = "map_reset_focus"})
end

function MapManager:mapTouchZoomIn(dt, speed)
    -- if not self._map then return end
    if cc.isDead(self._map) then return end
    self._map:mapTouchZoomIn(dt, speed)
end

function MapManager:mapTouchZoomOut(dt, speed)
    -- if not self._map then return end
    if cc.isDead(self._map) then return end
    self._map:mapTouchZoomOut(dt, speed)
end

function MapManager:forceCameraZoomToRunMax(params)
    self:dispatchEvent({name = "map_force_camera_zoom_to_runmax",params = params})
end

function MapManager:forecCameraZoomOutToDest(params)
    self:dispatchEvent({name = "map_force_camera_zoomout_to_dest",params = params})
end

function MapManager:forceCameraZoomToDest(params)
    self:dispatchEvent({name = "map_force_camera_zoom_to_dest",params = params})
end

function MapManager:stopParallaxActions()
    self:dispatchEvent({name = "map_stop_parallax_actions"})
end

function MapManager:saveMapLayerScale()
    self:dispatchEvent({name = "map_save_map_layer_scale"})
end

function MapManager:backToSaveMapLayerScale(params)
    self:dispatchEvent({name = "map_back_to_savemap_layer_scale",params = params})
end

function MapManager:mapOffsetWithCenter(params)
    self:dispatchEvent({name = "map_map_offset_with_center",params = params})
end

function MapManager:backMapOffsetToCenter(params)
    self:dispatchEvent({name = "map_back_map_offset_to_center",params = params})
end

function MapManager:stopCameraForBattle(params)
    self:dispatchEvent({name = "map_stop_camera_for_battle",params = params})
end

function MapManager:fadeNodeVisibility(params)
    self:dispatchEvent({name = "map_fade_node_visibility",params = params})
end

function MapManager:setFocusCharacterForInit(params)
    self:dispatchEvent({name = "map_set_focus_character_for_init",params = params})
end

function MapManager:setFocusCharacterNotInit(params)
    self:dispatchEvent({name = "map_set_focus_character_not_init",params = params})
end

function MapManager:forceCameraZoomIn(params)
    self:dispatchEvent({name = "map_force_camera_zoom_in",params = params})
end

function MapManager:fadeMapNode(params)
    self:dispatchEvent({name = "map_fade_map_node",params = params})
end

function MapManager:setFocusCharacter(params)
    self:dispatchEvent({name = "map_set_focus_character",params = params})
end

function MapManager:setFocusBattleActor(params)
    self:dispatchEvent({name = "map_set_focus_battle_actor",params = params})
end

function MapManager:setBattleCameraClamp(params)
    self:dispatchEvent({name = "map_set_battle_camera_clamp",params = params})
end

function MapManager:backNpcFocusToOldCharacter(params)
    self:dispatchEvent({name = "map_back_npc_focus_to_old_character",params = params})
end

function MapManager:mapToNormalColor(params)
    self:dispatchEvent({name = "map_map_to_normal_color",params = params})
end

function MapManager:playMapMusic()
    self:dispatchEvent({name = "map_play_map_music"})
end

function MapManager:stopMapMusic()
    self:dispatchEvent({name = "map_stop_map_music"})
end

function MapManager:initCamera()
    self:dispatchEvent({name = "map_init_camera"})
end

function MapManager:setMapMask(color,fadeTime)
    self:dispatchEvent({name = "map_set_mask",params = {color = color,fadeTime = fadeTime}})
end

function MapManager:resetMapMask(fadeTime)
    self:setMapMask(cc.c4b(255,255,255,255),fadeTime)
end

function MapManager:setMapWidth(width)
    self._mapWidth = width
end

function MapManager:getMapWidth()
    return self._mapWidth
end

function MapManager:setMapHeight(height)
    self._mapHeight = height
end

function MapManager:getMapHeight()
    return self._mapHeight
end

function MapManager:setCameraX(x)
    self._cameraX = x
end

function MapManager:getCameraX()
    return self._cameraX
end

function MapManager:setCameraY(y)
    self._cameraY = y
end

function MapManager:getCameraY()
    return self._cameraY
end

function MapManager:setGroundRoleScale(scale)
    self._groundRoleScale = scale
end

function MapManager:getGroundRoleScale()
    return self._groundRoleScale or 1.0
end

function MapManager:setGroundNpcScale(scale)
    self._groundNpcScale = scale
end

function MapManager:getGroundNpcScale()
    return self._groundNpcScale or 1.0
end

function MapManager:setGroundBossScale(scale)
    self._groundBossScale = scale
end

function MapManager:getGroundBossScale()
    return self._groundBossScale or 1.0
end

function MapManager:setGroundMercenaryScale(scale)
    self._groundMercenaryScale = scale
end

function MapManager:getGroundMercenaryScale()
    return self._groundMercenaryScale or 1.0
end

function MapManager:getMainCharacterPosX()
    local character = FieldManager:getMyCharacter()
    if character then
        local posX = character:toWorldPosition(0,0)
        return posX
    end
    return display.width/2
end

function MapManager:setExtraScaleRate(rate)
    self._extraScaleRate = rate
    if rate ~= 0 then
        self._oldExtraScaleRate = rate
    end
end

function MapManager:getExtraScaleRate()
    return self._extraScaleRate
end

function MapManager:getOldExtraScaleRate()
    return self._oldExtraScaleRate or 1.0
end

function MapManager:setMapScale(scale)
    self._scale = scale
end

function MapManager:getMapScale()
    return self._scale
end

function MapManager:setDefaultScale(scale)
    self._defaultScale = scale
end

function MapManager:getDefaultScale()
    return self._defaultScale
end

function MapManager:setMinScale(scale)
    self._minScale = scale
end

function MapManager:getMinScale()
    return self._minScale
end

function MapManager:setMaxScale(scale)
    self._maxScale = scale
end

function MapManager:getMaxScale()
    return self._maxScale
end

function MapManager:setForceCameraZoomOutToMin(toMin)
    self._forceCameraZoomOutToMin = toMin
end

function MapManager:isForceCameraZoomOutToMin()
    return self._forceCameraZoomOutToMin
end

function MapManager:setForceCameraZoomIn(zoomIn)
    self._forceCameraZoomIn = zoomIn
end

function MapManager:isForceCameraZoomIn()
    return self._forceCameraZoomIn
end

function MapManager:pauseRunCameraZoomForEvent(pause)
    self._eventPauseRunCameraZoom = pause
    if not pause then
        self:setForceCameraZoomOutToMin(false)
        self:setForceCameraZoomIn(false)
    end
end

function MapManager:isEventPauseRunCameraZoom()
    return self._eventPauseRunCameraZoom
end

function MapManager:setParallaxNode(parallaxNode)
    self._parallaxNode = parallaxNode
end

function MapManager:getParallaxNode()
    return self._parallaxNode
end

function MapManager:setGroundNode(groundNode)
    self._groundhNode = groundNode
end

function MapManager:getGroundNode()
    return self._groundhNode
end

function MapManager:getTargetPosition(touchPoint)
    local pos = nil
    if self:getGroundNode() then
        pos = self:getGroundNode():convertToNodeSpace(touchPoint)
    elseif self:getParallaxNode() then
        pos = self:getParallaxNode():convertToNodeSpace(touchPoint)
    end
    return pos
end

function MapManager:pauseAdjustCamera(pause)
    self._pauseAdjustCamera = pause
end

function MapManager:isPauseAdjustCamera()
    return self._pauseAdjustCamera
end

function MapManager:stopCameraZoomForStory(stop)
    self._stopCameraZoomForStory = stop
end

function MapManager:isStopCameraZoomForStory()
    return self._stopCameraZoomForStory
end

function MapManager:pauseEventAutoAdjustCamera(pause)
    self._eventAutoAdjustCamera = pause
end

function MapManager:isEventAutoAdjustCamera()
    return self._eventAutoAdjustCamera
end

function MapManager:getCurMinX(x)
    local section = self:getExtentSection(x)
    if section then
        return section.left
    end
    return self._borderLeftX
end

function MapManager:getCurMaxX(x)
    local section = self:getExtentSection(x)
    if section then
        return section.right
    end
    return self._borderRightX
end

function MapManager:checkInSameSecion(x1, x2)
    local section = self:getExtentSection(x1)
    if section then
        if x2 >= section.left and x2 <= section.right then
            return true
        end
    end

    return false
end

function MapManager:roundPosition(oldPosX, newPosX)

    local ret = newPosX
    local section = self:getExtentSection(oldPosX)
    if section then
        if newPosX < section.left then
            ret = section.left
        elseif newPosX  > section.right then
            ret = section. right
        end
    else -- 拉到最近的一个可行走点
        local minX = 99999
        for i, section in ipairs(self._mapExtents) do
            local dis1 = math.abs(section.left - oldPosX)
            local dis2 = math.abs(section.right - oldPosX)
            if dis1 < minX then
                minX = dis1
                ret = section.left
            end
            if dis2 < minX then
                minX = dis2
                ret = section.right
            end

            -- 剪枝
            if dis2 > dis1 then break end
        end
    end

    return ret
end

function MapManager:setHasChangeMapNextEvent(hasNext)
    self.mHasChangeMapNextEvent = hasNext
end

function MapManager:isHasChangeMapNextEvent()
    return self.mHasChangeMapNextEvent
end

function MapManager:isChangeToOwnMap(user)
    if not user then return true end

    local mapId = tonumber(user.map.id)
    local ownerUid = tonumber(user.map.ownerUid)
    local mapConfig = GD:queryMapById(mapId)
    if mapConfig then
        if tonumber(mapConfig.maptype) == 4 then--家园
            if ownerUid ~= nil and ownerUid ~= 0 and ownerUid ~= tonumber(app.session.uid) then
                return false
            end
        end
    end
    return true
end

function MapManager:getConfigMapScale()
    local scale = 1.5
    local hm = S("rolemenuzoomrate")
    local rate = ToNumber(hm)
    if rate then
       scale = ToNumber(hm) / 1000
    end
    return scale
end

function MapManager:cameraZoomIn()
    self:saveMapLayerScale()

    local time = 0.5
    local scale = self:getConfigMapScale()

    local function callback()
       -- self:pauseRunCameraZoomForEvent(false)
    end

    self:pauseRunCameraZoomForEvent(true)
    self:forceCameraZoomToDest({time = time,dstScale = scale,call = callback})
end

function MapManager:cameraZoomOut(time,callback,dstScale)
    local function call()
        if callback then
            callback()
        end
    end
    if not FieldManager:isUpdateFrame() then
        call()
        return
    end
    local tTime = time or 0.5
    local scale = dstScale or 1.0
    scale = self:getMaxScale()

    local function actionOver()
        self:pauseRunCameraZoomForEvent(false)
        call()
    end

    self:pauseRunCameraZoomForEvent(true)
    self:backToSaveMapLayerScale({time = tTime,callback = actionOver})
end

function MapManager:cameraOffset(time,offsetx,offsety)
    time = time or 0.5
    offsetx = offsetx or 0
    offsety = offsety or 0
    local scale = self:getConfigMapScale()
    self:mapOffsetWithCenter({time = time,offsetx = offsetx,offsety = offsety,scale = scale})
    NpcManager:hideAllNpcMark()
end

function MapManager:backCameraOffsetToOriginal(time,callback,notShow)
    time = time or 0.5
    self:backMapOffsetToCenter({time = time,callback = callback})
    if not notShow then
        NpcManager:showAllNpcMark()
    end
end

return MapManager
